/*
 * @Copyright: 
 * @Description: 
 * @Author: zhoujie
 * @Date: 2020-08-15 00:30:34
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2020-08-17 00:06:56
 */
#ifndef FLASH_API_H 
#define FLASH_API_H 

#include  "type.h"
#define LB_SIZE_512  1
#define LB_SIZE_1024 2
#define LB_SIZE_2048 4

#define SECT_NUM_PER_PAGE  4
#define PAGE_NUM_PER_BLK  64
#define SECT_NUM_PER_BLK  (SECT_NUM_PER_PAGE * PAGE_NUM_PER_BLK)
#define SECT_SIZE_B 512

#define SECT_BITS       2
#define PAGE_BITS       6
#define PAGE_SECT_BITS  8
#define BLK_BITS       24

#define NAND_STATE_FREE    -1
#define NAND_STATE_INVALID -2

#define SECT_MASK_IN_SECT 0x0003
#define PAGE_MASK_IN_SECT 0x00FC
#define PAGE_SECT_MASK_IN_SECT 0x00FF
#define BLK_MASK_IN_SECT  0xFFFFFF00
#define PAGE_BITS_IN_PAGE 0x003F
#define BLK_MASK_IN_PAGE  0x3FFFFFC0

#define PAGE_SIZE_B (SECT_SIZE_B * SECT_NUM_PER_PAGE)
#define PAGE_SIZE_KB (PAGE_SIZE_B / 1024)
#define BLK_SIZE_B  (PAGE_SIZE_B * PAGE_NUM_PER_BLK)
#define BLK_SIZE_KB (BLK_SIZE_B / 1024)

#define BLK_NO_SECT(sect)  (((sect) & BLK_MASK_IN_SECT) >> (PAGE_BITS + SECT_BITS))
#define PAGE_NO_SECT(sect) (((sect) & PAGE_MASK_IN_SECT) >> SECT_BITS)
#define SECT_NO_SECT(sect) ((sect) & SECT_MASK_IN_SECT)
#define BLK_PAGE_NO_SECT(sect) ((sect) >> SECT_BITS)
#define PAGE_SECT_NO_SECT(sect) ((sect) & PAGE_SECT_MASK_IN_SECT)
#define BLK_NO_PAGE(page)  (((page) & BLK_MASK_IN_PAGE) >> PAGE_BITS)
#define PAGE_NO_PAGE(page) ((page) & PAGE_MASK_IN_PAGE)
#define SECTOR(blk, page) (((blk) << PAGE_SECT_BITS) | (page))

#define BLK_MASK_SECT 0x3FFFFF00
#define PGE_MASK_SECT 0x000000FC
#define OFF_MASK_SECT 0x00000003
#define IND_MASK_SECT (PGE_MASK_SECT | OFF_MASK_SECT)
#define BLK_BITS_SECT 22
#define PGE_BITS_SECT  6
#define OFF_BITS_SECT  2
#define IND_BITS_SECT (PGE_BITS_SECT + OFF_BITS_SECT)
#define BLK_F_SECT(sect) (((sect) & BLK_MASK_SECT) >> IND_BITS_SECT)
#define PGE_F_SECT(sect) (((sect) & PGE_MASK_SECT) >> OFF_BITS_SECT)
#define OFF_F_SECT(sect) (((sect) & OFF_MASK_SECT))
#define PNI_F_SECT(sect) (((sect) & (~OFF_MASK_SECT)) >> OFF_BITS_SECT)
#define IND_F_SECT(sect) (((sect) & IND_MASK_SECT))
#define IS_SAME_BLK(s1, s2) (((s1) & BLK_MASK_SECT) == ((s2) & BLK_MASK_SECT))
#define IS_SAME_PAGE(s1, s2) (((s1) & (~OFF_MASK_SECT)) == ((s2) & (~OFF_MASK_SECT)))

typedef struct {
   int free;
   int ec;
   int update_ec;
}ST_BLK_STATE;
typedef struct {
  U32 free  :  1;          // sect is written
  U32 valid :  1;          // sect data is valid
  U32 lsn   : 30;          // last written valid data number (lba)
}ST_SECT_STATE;

typedef struct {
  ST_BLK_STATE state;                   // Erase Conunter
  ST_SECT_STATE sect[SECT_NUM_PER_BLK]; // Logical Sector Number
  S32 freePageCnt : 10;                 // free page counter
  S32 invalidPageCnt : 10;              // invalide page counter
  S32 lastWritePageIdx : 12;            // last written page number
  int pageStatus[PAGE_NUM_PER_BLK];     // 0:data ; 1:map table ; -1 invalid
} ST_NAND_BLK_INFO;

typedef struct {
  U32 NandReadCnt;
  U32 NandWriteCnt;
  U32 NandEraseCnt;
  U32 NandOOBReadCnt;
  U32 NandOOBWriteCnt;
  U32 NandGCReadCnt;
  U32 NandGCWriteCnt;
} ST_NAND_STAT_INFO;

typedef struct {
  U32 allBlkNum;
  U32 freeBlkNum;
  U32 minBlkNum;
  U32 curBlkIdx;
  ST_NAND_BLK_INFO *pstNandBlkInfo;    // Nand全局变量结构体指针
  ST_NAND_STAT_INFO *pstNandStatInfo;  // Nand操作统计全局结构体
} ST_NAND_GI_INFO;

typedef enum {
    EN_NAND_PAGE_READ ,
    EN_NAND_PAGE_WRITE ,
    EN_NAND_BLOCK_ERASE,
    EN_NAND_OOB_READ,
    EN_NAND_OOB_WRITE,
    EN_GC_PAGE_READ,
    EN_GC_PAGE_WRITE
} EN_NAND_OPERATION; // Nand操作类型

typedef enum {
  EN_FLASH_NORMAL_READ,   // 正常数据读取，是模拟比对
  EN_FLASH_GC_READ,       // GC数据读取
  EN_FLASH_GC_FORMAT_READ // 格式化掉Nand中不存在但MAP中记录的LBA，过程中还会比较数据一致性
}EN_FLASH_READ_TYPE;

extern ST_NAND_GI_INFO *g_pstNandGi;

void Flash_EndAndClear(void);
U08 Flash_NandGIInit(U32 AllBlkNum, U08 minFreeBlkNum);
void Flash_NandStatPrint(FILE *outFP);
void Flash_NandStat(EN_NAND_OPERATION enOption);
S16 Flash_NandOOBRead(U32 phySectAddr);

#endif